package ru.evga.billboard.graph;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.swing.DefaultBoundedRangeModel;

import ru.evga.billboard.common.JSON;
import ru.evga.billboard.common.JSONObject;
import ru.evga.billboard.graph.preference.IParamChangeListener;
import ru.evga.billboard.graph.preference.Param;
import ru.evga.billboard.graph.preference.GraphSettings;


public class FrameSet
    extends DefaultBoundedRangeModel
    implements JSONObject
{
    private List<Frame> frames = new ArrayList<Frame>();
    private int currentFrame;
    private Set<IFrameChangeListener> listener = new HashSet<FrameSet.IFrameChangeListener>();

    public static interface IFrameChangeListener
    {
        void onChangeFrame(int frame);
    }

    public void addListener(IFrameChangeListener listener)
    {
        this.listener.add(listener);
    }

    public void removeListener(IFrameChangeListener listener)
    {
        this.listener.remove(listener);
    }

    public FrameSet(GraphSettings preference)
    {
        setMaximum(preference.frameCount.getValue()-1);
        for (int i = 0; i < preference.frameCount.getValue(); i++)
        {
            addFrame();
        }
        preference.frameCount.addChangeListener(new IParamChangeListener<Integer>()
        {
            public void onParamChange(Param<Integer> param)
            {
                Integer count = param.getValue();
                FrameSet.this.setMaximum(count-1);
                if (frames.size() < count)
                {
                    while(frames.size() < count)
                    {
                        addFrame();
                    }
                }
                else if (frames.size() > count)
                {
                    while (frames.size() > count && frames.size() > 0)
                    {
                        frames.remove(frames.size() - 1);
                    }
                }
                if (currentFrame >= count)
                {
                    currentFrame = count - 1;
                }

            }
        });
    }

    public Frame addFrame()
    {
        Frame f = new Frame();
        frames.add(f);
        return f;
    }

    public int getFrameCount()
    {
        return frames.size();
    }

    public Frame getFrame(int frameNo)
    {
        Frame frame = frames.get(frameNo);
        return frame;
    }

    public void setCurrentFrame(int currentFrame)
    {
        if (frames.size() <= currentFrame)
        {
            return;
        }
        this.currentFrame = currentFrame;
        super.setValue(currentFrame);
        if (listener != null)
        {
            IFrameChangeListener [] a;
            synchronized (listener)
            {
                a = listener.toArray(new IFrameChangeListener[listener.size()]);
            }
            for (IFrameChangeListener l : a)
            {
                if (l != null)
                {
                    l.onChangeFrame(currentFrame);
                }
            }
        }
    }

    public Frame getCurrentFrame()
    {
        return frames.get(currentFrame);
    }

    @Override
    public void setValue(int n)
    {
        setCurrentFrame(n);
        super.setValue(n);
    }

    @Override
    public Map toJSONMap()
    {
        return Collections.singletonMap("data", frames);
    }
    
    public void fromJSONMap(Map<String, Object> map)
    {
        Object[] objects = (Object[])map.get("data");
        frames.clear();
        for(Object o : objects)
        {
            Frame f = new Frame();
            f.fromJSONMap((Map<String, Object>)o);
            frames.add(f);
        }
    }
    
    public byte[] getContentAsBytes()
    {
        return JSON.toString(this).getBytes();
    }

    public void setContentFromBytes(byte[] data)
    {
        Object parse = JSON.parse(new String(data));
        fromJSONMap((Map<String, Object>)parse);
    }

    
}
